﻿// Copyright 2009 Mike Geise
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

namespace Falcon.Core.Services
{
	using System;
	using System.Collections.Generic;
	using System.Globalization;
	using System.IO;
	using Falcon.Core.Collections;
	using Falcon.Core.Domain;
	using Falcon.Core.Domain.Repositories;
	using Falcon.Core.Domain.Services;
	using Falcon.Core.Domain.Values;
	using Falcon.Core.Extensions;

	public class UserAvatarService : IUserAvatarService
	{
		/// <summary>
		/// Initializes a new instance of the <see cref="UserAvatarService"/> class.
		/// </summary>
		/// <param name="identityService">The identity service.</param>
		/// <param name="fileService">The file service.</param>
		/// <param name="userService">The user service.</param>
		/// <param name="userProfileService">The user profile service.</param>
		/// <param name="userAvatarRepository">The user avatar repository.</param>
		public UserAvatarService(
			IIdentityService identityService,
			IFileService fileService,
			IUserService userService,
			IUserProfileService userProfileService,
			IUserAvatarRepository userAvatarRepository)
		{
			this.IdentityService = identityService;
			this.FileService = fileService;
			this.UserService = userService;
			this.UserProfileService = userProfileService;
			this.UserAvatarRepository = userAvatarRepository;
		}

		/// <summary>
		/// Gets or sets the identity service.
		/// </summary>
		/// <value>The identity service.</value>
		public IIdentityService IdentityService
		{
			get;
			private set;
		}

		/// <summary>
		/// Gets or sets the file service.
		/// </summary>
		/// <value>The file service.</value>
		public IFileService FileService
		{
			get;
			private set;
		}

		/// <summary>
		/// Gets or sets the user service.
		/// </summary>
		/// <value>The user service.</value>
		public IUserService UserService
		{
			get; 
			private set;
		}

		/// <summary>
		/// Gets or sets the user profile service.
		/// </summary>
		/// <value>The user profile service.</value>
		public IUserProfileService UserProfileService
		{
			get; 
			private set;
		}

		/// <summary>
		/// Gets or sets the user avatar repository.
		/// </summary>
		/// <value>The user avatar repository.</value>
		public IUserAvatarRepository UserAvatarRepository
		{
			get; 
			private set;
		}

		/// <summary>
		/// Gets the user avatar by id.
		/// </summary>
		/// <param name="id">The id.</param>
		/// <returns></returns>
		public UserAvatar GetById(int id)
		{
			var avatar = this.UserAvatarRepository.GetById(id);

			var profile = this.UserProfileService.GetBy(new UserProfileSpecification
			{
				UserId = avatar.UserId
			});

			avatar.IsAssigned = profile.AvatarId.Equals(avatar.Id);

			return avatar;
		}

		/// <summary>
		/// Gets all the user avatars.
		/// </summary>
		/// <returns></returns>
		public IList<UserAvatar> GetAll()
		{
			return this.GetPaged(new UserAvatarSpecification()).Items;
		}

		/// <summary>
		/// Gets all the user avatars.
		/// </summary>
		/// <param name="specification">The <see cref="UserAvatarSpecification"/>.</param>
		/// <returns></returns>
		public IPagedList<UserAvatar, UserAvatarSpecification> GetPaged(UserAvatarSpecification specification)
		{
			var avatars = this.UserAvatarRepository.GetPaged(specification);

			if (specification.UserId > 0)
			{
				var profile = this.UserProfileService.GetBy(new UserProfileSpecification
				{
					UserId = specification.UserId
				});

				if (profile != null)
				{
					avatars.ForEach(x => x.IsAssigned = profile.AvatarId.Equals(x.Id));
				}
			}

			return avatars;
		}

		/// <summary>
		/// Creates the user avatar.
		/// </summary>
		/// <returns></returns>
		public UserAvatar Create()
		{
			var identity = this.IdentityService.Current;

			return identity == null ? new UserAvatar() : new UserAvatar
			{
				UserId = identity.Id
			};
		}

		/// <summary>
		/// Selects the specified avatar.
		/// </summary>
		/// <param name="avatar">The avatar.</param>
		public void Select(UserAvatar avatar)
		{
			var profile = this.UserProfileService.GetBy(new UserProfileSpecification
			{
				UserId = avatar.UserId
			});

			profile.Avatar = avatar;

			this.UserProfileService.Update(profile);
		}

		/// <summary>
		/// Inserts the specified user avatar into the storage.
		/// </summary>
		/// <param name="avatar">The <see cref="UserAvatar"/>.</param>
		public void Insert(UserAvatar avatar)
		{
			this.UserAvatarRepository.Insert(avatar);
		}

		/// <summary>
		/// Inserts the specified user avatar into the storage.
		/// </summary>
		/// <param name="avatar">The avatar.</param>
		/// <param name="value">The value.</param>
		public void Insert(UserAvatar avatar, UserAvatarCreate value)
		{
			value.Validate();

			var path = GetPath();
			var result = this.FileService.Save(value.Source, path);
			var identity = this.IdentityService.Current;

			avatar.UserId = identity.Id;
			avatar.FileName = result.FileName;
			avatar.FileDiskName = result.FileDiskName;
			avatar.FilePath = result.FilePath.Replace("\\", "/");
			avatar.FileType = result.FileType;
			avatar.Created = DateTime.Now;

			this.Insert(avatar);
			this.Select(avatar);
		}

		/// <summary>
		/// Updates the specified user avatar in the storage.
		/// </summary>
		/// <param name="avatar">The <see cref="UserAvatar"/>.</param>
		public void Update(UserAvatar avatar)
		{
			this.UserAvatarRepository.Update(avatar);
		}

		/// <summary>
		/// Deletes the specified user avatar in the storage.
		/// </summary>
		/// <param name="avatar">The <see cref="UserAvatar"/>.</param>
		public void Delete(UserAvatar avatar)
		{
			if (avatar.IsAssigned)
			{
				var profile = this.UserProfileService.GetBy(new UserProfileSpecification
				{
					UserId = avatar.UserId
				});

				profile.Avatar = null;
				profile.AvatarId = 0;

				this.UserProfileService.Update(profile);
			}

			FileService.Delete(avatar.FilePath.AsPath());

			this.UserAvatarRepository.Delete(avatar);
		}

		/// <summary>
		/// Gets the avatar path.
		/// </summary>
		/// <returns></returns>
		private static string GetPath()
		{
			// current date
			var date = DateTime.Now;

			// month/day/year
			var year = date.Year.ToString(CultureInfo.InvariantCulture);
			var month = Path.Combine(year, date.Month.ToString(CultureInfo.InvariantCulture));
			var day = Path.Combine(month, date.Day.ToString(CultureInfo.InvariantCulture));

			// path_to_attachments/month/day/year
			var path = Path.Combine(Settings.Users.AvatarPath, day);

			// create directory when needed
			var directory = new DirectoryInfo(path.AsPath());

			if (!directory.Exists)
			{
				directory.Create();
			}

			return path;
		}
	}
}